package com.atjava.nebula.web.action;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManagerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.kie.api.KieServices;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.EnvironmentName;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.manager.RuntimeEngine;
import org.kie.api.runtime.manager.RuntimeEnvironmentBuilder;
import org.kie.api.runtime.manager.RuntimeManager;
import org.kie.api.runtime.manager.RuntimeManagerFactory;
import org.kie.api.task.TaskService;
import org.kie.api.task.model.TaskSummary;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.atjava.nebula.core.dao.ibatis.Condition;
import com.atjava.nebula.core.exception.baseExp.BusinessException;
import com.atjava.nebula.core.exception.baseExp.SystemException;
import com.atjava.nebula.core.model.TreeModel;
import com.atjava.nebula.core.page.Page;
import com.atjava.nebula.core.service.GenericService;
import com.atjava.nebula.core.tablexml.view.Grid;
import com.atjava.nebula.core.tablexml.view.Query;
import com.atjava.nebula.core.tablexml.view.Tree;
import com.atjava.nebula.core.util.context.SpringContextHolder;
import com.atjava.nebula.core.util.func.StringUtil;
import com.atjava.nebula.core.util.tree.TreeUtils;
import com.atjava.nebula.frames.menu.SysMenu;
import com.atjava.nebula.frames.menu.service.MenuService;
import com.atjava.nebula.web.collections.GridDataList;
import com.atjava.nebula.web.constant.ProjectConst;
import com.atjava.nebula.web.view.XmlViewManager;

@Controller
@RequestMapping("/base/list")
public class ListAction extends BaseViewAction {

	@RequestMapping("/view/**")
	public ModelAndView listView(
			HttpServletRequest request, 
			HttpServletResponse response,
			ModelMap modelMap) throws SystemException, BusinessException {
		
		UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		Set<GrantedAuthority> authorities = (Set<GrantedAuthority>) userDetails.getAuthorities();
		
		MenuService menuService = (MenuService)SpringContextHolder.getBean
				(ProjectConst.SERVICE_KEY_MENU);
//		SysMenu sysMenu = menuService.getMenuObject();
		SysMenu sysMenu = menuService.getUserCurrentMenuObject(authorities);
		
		modelMap.addAttribute(MODEL_KEY_SYSMENU, sysMenu);
		modelMap.addAttribute(MODEL_KEY_CATALOG, catalog);
		modelMap.addAttribute(MODEL_KEY_XMLVIEW, xmlview);
		modelMap.addAttribute(MODEL_KEY_VIEWCFG, viewConfig);
		
		return new ModelAndView(VIEW_PATH_LIST, modelMap);
	}
	
	//@RequestMapping("/view/**")
	public ModelAndView listView1(
			HttpServletRequest request, 
			HttpServletResponse response,
			ModelMap modelMap) throws SystemException, BusinessException {
		
		UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		String username = userDetails.getUsername();
		
		MenuService menuService = (MenuService)SpringContextHolder.getBean
				(ProjectConst.SERVICE_KEY_MENU);
		SysMenu sysMenu = menuService.getMenuObject();
		
		modelMap.addAttribute(MODEL_KEY_SYSMENU, sysMenu);
		modelMap.addAttribute(MODEL_KEY_CATALOG, catalog);
		modelMap.addAttribute(MODEL_KEY_XMLVIEW, xmlview);
		modelMap.addAttribute(MODEL_KEY_VIEWCFG, viewConfig);
		
		
		/**********************************************/
		
		
		/*KieServices kservices = KieServices.Factory.get();
			KieContainer kContainer = kservices.getKieClasspathContainer();
			KieBase kbase = kContainer.getKieBase("kbase");
			
			
		
			EntityManagerFactory emf = (EntityManagerFactory) SpringContextHolder.getBean("jbpmEMF");
		
			AbstractPlatformTransactionManager aptm = (AbstractPlatformTransactionManager) SpringContextHolder.getBean("jbpmTxManager");	

			
			RuntimeEnvironmentBuilder builder = RuntimeEnvironmentBuilder.Factory.get().newDefaultBuilder()
//	        	.addAsset(kservices.getResources().newClassPathResource("sample.bpmn"), ResourceType.BPMN2)
					 
					  * don't need to set it on environment, there is special method to accept EMF
					 
			    .addEnvironmentEntry(EnvironmentName.TRANSACTION_MANAGER, aptm)
			    /**
			     * This will be created automatically when transaction manager (line above) is spring object
			    
			    .entityManagerFactory(emf).knowledgeBase(kbase) ;*/
		
		KieServices kservices = KieServices.Factory.get();
		EntityManagerFactory emf = (EntityManagerFactory) SpringContextHolder.getBean("jbpmEMF");
		AbstractPlatformTransactionManager aptm = (AbstractPlatformTransactionManager) SpringContextHolder.getBean("jbpmTxManager");
		
		RuntimeEnvironmentBuilder builder = RuntimeEnvironmentBuilder.Factory.get().newDefaultBuilder()
				.addAsset(kservices.getResources().newClassPathResource("bpmn/sample.bpmn"), ResourceType.BPMN2)
				.addEnvironmentEntry(EnvironmentName.TRANSACTION_MANAGER, aptm)
				.entityManagerFactory(emf);
				//knowledgeBase(kbase);
		
		//RuntimeEnvironmentFactoryBean environment = (RuntimeEnvironmentFactoryBean)SpringContextHolder.getBean("runtimeEnvironment");
		//org.kie.api.io.Resource res = ResourceFactory.newClassPathResource("resources/bpmn/sample.bpmn");
		//environment.getAssets().put(res, ResourceType.BPMN2);
		
		
        RuntimeManager manager = RuntimeManagerFactory.Factory.get().newSingletonRuntimeManager
        		(builder.get(), "com.sample.bpmn.hello");
        
        RuntimeEngine engine = manager.getRuntimeEngine(null);
        KieSession ksession = engine.getKieSession();
        TaskService taskService = engine.getTaskService();
        
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("recipient", "kylin");
        ksession.startProcess("org.jbpm.demo.rewards", params);
        
		// let john execute Task 1
		List<TaskSummary> list = taskService.getTasksAssignedAsPotentialOwner("john", "en-UK");
		TaskSummary task = list.get(0);
		taskService.start(task.getId(), "john");
		taskService.complete(task.getId(), "john", null);

		// let mary execute Task 2
		list = taskService.getTasksAssignedAsPotentialOwner("mary", "en-UK");
		task = list.get(0);
		taskService.start(task.getId(), "mary");
		taskService.complete(task.getId(), "mary", null);

		manager.disposeRuntimeEngine(engine);
		
		return new ModelAndView(VIEW_PATH_LIST, modelMap);
	}
	
	@RequestMapping("/config/**")
	@ResponseBody
	public Grid viewConfig(HttpServletRequest request, 
			@RequestParam(REQ_PARAM_GRIDID) String gridId,
			HttpServletResponse response) throws SystemException, BusinessException {
		
		Grid grid = XmlViewManager.getGrid(viewConfig, gridId);
		return grid;
	}
	
	@RequestMapping("/grid-data/**")
	@ResponseBody
	public GridDataList listGridData(HttpServletRequest request, 
			HttpServletResponse response,
			@RequestParam(REQ_PARAM_GRIDID) String gridId) throws SystemException, BusinessException {
		
		//search condition
		Condition cond = new Condition();
		String queryId = request.getParameter(REQ_PARAM_QUERYID);
		if(StringUtils.isNotBlank(queryId)){
			Query query = XmlViewManager.getQuery(viewConfig, queryId);
			cond = getConditionFromRequest(request, query);
		}
		
		//grid
		Grid grid = XmlViewManager.getGrid(viewConfig, gridId);
		String dataset = grid.getDataset();
		if(StringUtils.isBlank(dataset)){
			throw new SystemException("grid ["+grid.getId()+"] dataset can not be null.");
		}
		
		//get service
		GenericService<?,?> baseService = getService(dataset);
		
		List<?> dataList = null;
		
		//background paging
		if(grid.isPage() && grid.isBackPage()){
			//record paging
			String pageNo = request.getParameter(REQ_PARAM_PAGENO);
			int pageNum = 1;
			if(!StringUtils.isBlank(pageNo)){
				pageNum = Integer.parseInt(pageNo);
			}

			//record list
			Page<?> page = baseService.page( cond, pageNum, grid.getPageSize());
			dataList = page.getResult();
		
		}else{
			dataList = baseService.list(cond);
		}
		
		int splitIndex = dataset.indexOf(".");
		String catalog = dataset.substring(0,splitIndex);
		String entity = dataset.substring(splitIndex+1);
		
		Class<?> entityClass = XmlViewManager.getEntityClass(catalog, entity);
		if(grid.isTree() && TreeUtils.isTreeModel(entityClass)){
			dataList = TreeUtils.sortTreeList((List<TreeModel>) dataList);
		}
		
		GridDataList gridDataList = new GridDataList();
		gridDataList.setConfig(grid);
		gridDataList.setRecords(dataList);
		
		return gridDataList;
		
	}
	
	@SuppressWarnings("unchecked")
	@RequestMapping("/tree-data/**")
	@ResponseBody
	public Object listTreeData(HttpServletRequest request,
			@RequestParam(REQ_PARAM_TREEID) String treeId,
			HttpServletResponse response) throws SystemException, BusinessException {
		
		Tree tree = XmlViewManager.getTree(viewConfig, treeId);
		GenericService<?,?> baseService = getService(tree.getDataset());
		
		//record list
		Condition cond = new Condition();
		List<?> dataList = baseService.list(cond);
		dataList = TreeUtils.getTreeObjectList((List<TreeModel>) dataList);
		return dataList;
		
	}
	
	@RequestMapping("/data/**")
	@ResponseBody
	public Object listData(HttpServletRequest request,
			@RequestParam(REQ_PARAM_CATALOG) String catalog,
			@RequestParam(REQ_PARAM_ENTITY) String entity,
			HttpServletResponse response) throws SystemException, BusinessException {
		
		GenericService<?,?> baseService = getService(catalog,entity);
		//record list
		Condition cond = new Condition();
		return baseService.list(cond);
		
	}
	
	@RequestMapping("/autoComplete/**") 
	@ResponseBody 
	public Object autoData(HttpServletRequest request, 
			@RequestParam(REQ_PARAM_CATALOG) String catalog, 
			@RequestParam(REQ_PARAM_ENTITY) String entity, 
			@RequestParam(REQ_PARAM_COMPNAME) String compname,
			@RequestParam("keyword") String keyword,
			ModelMap modelMap) throws SystemException, BusinessException { 

		GenericService<?, ?> baseService = getService(catalog, entity); 
		//record list 
		Condition cond = new Condition(); 
		String condition = StringUtil.toUnderlineName(compname) +" LIKE " +"'%"+keyword+"%'";
		cond.addCriterion(condition);
		return  baseService.list(cond); 
	}
}
